package com.fivefu.core.gb28181.listner;

import com.alibaba.fastjson.JSON;
import com.fivefu.core.gb28181.utils.SipMessageUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.sip.*;
import javax.sip.header.CSeqHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.TooManyListenersException;

public class SipServerLayer implements SipListener {

    private Logger logger = LoggerFactory.getLogger(SipServerLayer.class);

    String ip;

    Integer port;

    private SipFactory sipFactory;

    private SipStack sipStack;

    private ListeningPoint tcp, udp;

    private SipProvider tcpProvider, udpProvider;

    private Map<String, SipRequestListener> sipListenerMap = new HashMap<>();

    private Map<String, SipResponseListener> sipResponseListenerMap = new HashMap<>();

    public void addSipListener(String method, SipRequestListener sipRequestListener){
        sipListenerMap.put(method,sipRequestListener);
    }

    public void addSipResponseListener(String method, SipResponseListener sipResponseListener){
        sipResponseListenerMap.put(method,sipResponseListener);
    }

    @SuppressWarnings("deprecation")
    public SipServerLayer(String ip, int port) throws SipException, InvalidArgumentException, TooManyListenersException {
        sipFactory = SipFactory.getInstance();
        sipFactory.setPathName("gov.nist");

        Properties sipProperties = new Properties();
        sipProperties.setProperty("gov.nist.javax.sip.TRACE_LEVEL", "DEBUG");
        sipProperties.setProperty("gov.nist.javax.sip.DEBUG_LOG", "sip_debug_log.txt");
        sipProperties.setProperty("gov.nist.javax.sip.SERVER_LOG", "sip_server_log.txt");

//        sipProperties.setProperty("javax.sip.STACK_NAME", "srymy-GB28181");
        sipProperties.setProperty("javax.sip.STACK_NAME","GB28181_SIP");
        sipProperties.setProperty("javax.sip.IP_ADDRESS", ip);

        sipStack = sipFactory.createSipStack(sipProperties);
        sipFactory.createHeaderFactory();
        sipFactory.createMessageFactory();
        sipFactory.createAddressFactory();
        sipStack.start();

        createTcpListenerPoint(ip, port);
        createUdpListenerPoint(ip, port);

    }

    /**
     * 监听tcp协议
     *
     * @param ip
     * @param port
     * @throws SipException
     * @throws InvalidArgumentException
     * @throws TooManyListenersException
     */
    public void createTcpListenerPoint(String ip, int port) throws SipException, InvalidArgumentException, TooManyListenersException {
        tcp = sipStack.createListeningPoint(ip, port, "tcp");
        tcpProvider = sipStack.createSipProvider(tcp);
        tcpProvider.addSipListener(this);
    }

    /**
     * 监听udp协议
     *
     * @param ip
     * @param port
     * @throws SipException
     * @throws InvalidArgumentException
     * @throws TooManyListenersException
     */
    public void createUdpListenerPoint(String ip, int port) throws SipException, InvalidArgumentException, TooManyListenersException {
        udp = sipStack.createListeningPoint(ip, port, "udp");
        udpProvider = sipStack.createSipProvider(udp);
        udpProvider.addSipListener(this);
    }

    /**
     * 接受请求消息
     *
     * @param requestEvent
     */
    @Override
    public void processRequest(RequestEvent requestEvent) {
        Request request = requestEvent.getRequest();
        String method = request.getMethod();
        if (request == null){
            System.out.println("request is null");
            return;
        }
        switch (method) {
            case Request.INVITE:
                break;
            case Request.BYE:
                break;
            default:
                break;
        }
        System.out.println("has request");
        System.out.println("method:" + method);

        if (sipListenerMap.containsKey(method)){
            SipRequestListener sipListener = sipListenerMap.get(method);
            try {
                sipListener.process(requestEvent);
            } catch (SipException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            } catch (InvalidArgumentException e) {
                e.printStackTrace();
            }
        }else{
            System.out.println("has request");
            System.out.println("method:" + method);
        }
    }

    /**
     * 接受响应消息
     *
     * @param responseEvent
     */
    @Override
    public void processResponse(ResponseEvent responseEvent) {
        System.out.println("response");
        Response response = responseEvent.getResponse();
        try {
            CSeqHeader cSeqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
            String method = cSeqHeader.getMethod().toUpperCase();
            if (sipResponseListenerMap.containsKey(method)){
                SipResponseListener sipResponseListener = sipResponseListenerMap.get(method);
                try {
                    sipResponseListener.process(responseEvent);
                } catch (SipException e) {
                    e.printStackTrace();
                } catch (ParseException e) {
                    e.printStackTrace();
                } catch (InvalidArgumentException e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public void processTimeout(TimeoutEvent timeoutEvent) {
        logger.error("Previous message not sent: timeout");
    }

    @Override
    public void processIOException(IOExceptionEvent ioExceptionEvent) {
        logger.error("Previous message not sent: I/O Exception");
    }

    @Override
    public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
        logger.info("Transaction结束,evt: {}",transactionTerminatedEvent);
    }

    @Override
    public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
        logger.info("会话结束：CallId: {}, DialogId: {}",dialogTerminatedEvent.getDialog().getCallId(), dialogTerminatedEvent.getDialog().getDialogId());
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }

    public Integer getPort() {
        return port;
    }

    public void setPort(Integer port) {
        this.port = port;
    }

    public SipFactory getSipFactory() {
        return sipFactory;
    }

    public void setSipFactory(SipFactory sipFactory) {
        this.sipFactory = sipFactory;
    }

    public SipStack getSipStack() {
        return sipStack;
    }

    public void setSipStack(SipStack sipStack) {
        this.sipStack = sipStack;
    }

    public SipProvider getTcpProvider() {
        return tcpProvider;
    }

    public void setTcpProvider(SipProvider tcpProvider) {
        this.tcpProvider = tcpProvider;
    }

    public SipProvider getUdpProvider() {
        return udpProvider;
    }

    public void setUdpProvider(SipProvider udpProvider) {
        this.udpProvider = udpProvider;
    }
}
